#ifndef __PFS__DEFINE_H
#define __PFS_DEFINE_H

#include <map>
#include <ext/hash_map>
#include <set>
#include <stdint.h>
#include <string.h>
#include <vector>
using namespace std;


/*namespace __gnu_cxx
{
    template<> struct hash<uint64_t>
    {//using for hash_map
        uint64_t operator()(uint64_t x) const
        {
            return x;
        }
    };

}*/


namespace PFS
{
    const string DELEMIT = "/";
    struct str_equal
    {
        bool operator()(const char* s1, const char* s2) const
        {
            return strcmp(s1, s2) == 0;
        }
    };

    vector<string> split(const string& src, const string& delimit)
    {
        vector<string> strs;
        
        int delimit_len = delimit.size();
        int last_position = 0, index = -1;

        while(-1 != (index = src.find(delimit, last_position)))
        {
            if(index != last_position)
                strs.push_back(src.substr(last_position, index - last_position));
            last_position = index + delimit_len;
        }

        string last_str = src.substr(last_position);
        if(!last_str.empty())
            strs.push_back(last_str);
        return strs;
    }

    string join(const vector<string>& vec, const string& token)
    {
        string str;
        for(int i = 0; i < vec.size(); i++)
        {
            str.append(vec[i]);
            if( i != (vec.size() - 1))
                str.append(token);
        }
        return str;
    }

    class BlockLocate;
    class ServerLocate;
    struct Throughput
    {
        int64_t write_byte;
        int64_t write_file_count;
        int64_t read_byte;
        int64_t read_file_count;
    };

    enum DataServerLiveStatus
    {
        DATASERVER_ALIVE = 0x00,
        DATASERVER_DEAD
    };

    enum ServerRole
    {
        Master_Server = 0,
        Slave_Server
    };

    struct DataServerInfo
    {
        uint64_t id;
        int64_t use_capacity;
        int64_t total_capacity;
        int32_t current_load;
        int32_t block_count;
        int32_t last_update_time;
        int32_t stattup_time;
        Throughput total_tp;
        int32_t current_time;
        DataServerLiveStatus status;
        string addr; //ip:port  192.168.0.50:8998
    };

    struct WriteDataInfo
    {
        uint32_t block_id;
        int32_t offset;
        int64_t length;
        ServerRole is_server;
    };

/*    struct DataInfo
    {//data in block whick belongs to a file
        uint32_t block_id;
        uint64_t offset_in_block; // 
        uint32_t index_of_file; //the index-th of the file
        uint64_t length;
        string file_name;
    };*/
    struct BlockInfo
    {//support variable block size, each block is a chunk of file content
        uint32_t block_id;
        int32_t version;
        int32_t index_of_file;
        int32_t size;
        int32_t del_file_count;
        int32_t del_size;
        string file_name;

        BlockInfo()
        {
            memset(this, 0, sizeof(BlockInfo));
        }

        bool operator==(const BlockInfo& rhs) const
        {
            return block_id == rhs.block_id && version == rhs.version && index_of_file == rhs.index_of_file && size == rhs.size && del_file_count == rhs.del_file_count && del_size == rhs.del_size; 
        }

        BlockInfo& operator=(const BlockInfo& rhs)
        {
            block_id = rhs.block_id;
            version = rhs.version;
            index_of_file = rhs.index_of_file;
            size = rhs.size;
            del_file_count = rhs.del_file_count;
            del_size = rhs.del_size;
            file_name = rhs.file_name;
            return *this;
        }
    };

    typedef __gnu_cxx::hash_map<uint32_t, BlockLocate*, __gnu_cxx::hash<uint32_t> > BLOCK_MAP;
    typedef __gnu_cxx::hash_map<uint64_t, ServerLocate*, __gnu_cxx::hash<uint64_t> > SERVER_MAP;

    typedef BLOCK_MAP::iterator BLOCK_MAP_ITER;
    typedef SERVER_MAP::iterator SERVER_MAP_ITER;

    typedef map<uint64_t, vector<uint32_t> > EXPIRE_BLOCK_LIST;
    typedef map<uint64_t, vector<uint32_t> >::iterator EXPIRE_BLOCK_LIST_ITER;
}

#endif
